#!/bin/bash
# Copyright (C) 2017 Ingrasys, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

VERSION="1.0.0"
TRUE=200
FALSE=404

TYPE=${1}
PORT=${2}

# port number
MIN_PORT=0
MAX_PORT=53

# INDEX of value field in array
SI_PRE_IDX=1
SI_POST_IDX=2
SI_MAIN_IDX=3
SI_AMP_IDX=4
SI_DRI_IDX=5

# type string
AOC_TYPE="aoc"
DAC_TYPE="dac"

# si value for bcm command
SI_VAL=""

# "PRE POST MAIN AMP DRIVERMODE" for each port in array
# TODO: need to change aoc si value when available
xe_aoc_si_value=( 
    "0x00 0x3e 0x32 0xf 0x0"      #port  0 
    "0x00 0x3a 0x36 0xf 0x0"      #port  1 
    "0x00 0x3a 0x36 0xf 0x0"      #port  2
    "0x00 0x38 0x38 0xf 0x0"      #port  3
    "0x00 0x37 0x39 0xf 0x0"      #port  4
    "0x00 0x2e 0x42 0xf 0x0"      #port  5
    "0x00 0x33 0x3d 0xf 0x0"      #port  6
    "0x00 0x30 0x40 0xc 0x0"      #port  7
    "0x00 0x2f 0x43 0xe 0x0"      #port  8
    "0x00 0x2d 0x43 0xc 0x0"      #port  9
    "0x00 0x2c 0x44 0xc 0x0"      #port 10
    "0x00 0x2d 0x43 0xc 0x0"      #port 11
    "0x00 0x29 0x47 0xc 0x0"      #port 12
    "0x00 0x28 0x48 0xc 0x0"      #port 13
    "0x00 0x29 0x47 0xa 0x0"      #port 14
    "0x00 0x29 0x47 0xf 0x0"      #port 15
    "0x00 0x18 0x58 0x9 0x0"      #port 16
    "0x00 0x1d 0x53 0x9 0x0"      #port 17
    "0x00 0x1c 0x54 0x9 0x0"      #port 18
    "0x00 0x1c 0x54 0x9 0x0"      #port 19
    "0x00 0x1c 0x54 0x9 0x0"      #port 20
    "0x00 0x1c 0x54 0x9 0x0"      #port 21
    "0x00 0x1c 0x54 0x9 0x0"      #port 22
    "0x00 0x1c 0x54 0x9 0x0"      #port 23
    "0x00 0x1c 0x54 0x8 0x0"      #port 24
    "0x00 0x1c 0x54 0x8 0x0"      #port 25
    "0x00 0x18 0x58 0x8 0x0"      #port 26
    "0x00 0x18 0x58 0x8 0x0"      #port 27
    "0x00 0x14 0x5c 0x8 0x0"      #port 28
    "0x00 0x19 0x57 0x8 0x0"      #port 29
    "0x00 0x19 0x57 0x8 0x0"      #port 30
    "0x00 0x19 0x57 0x8 0x0"      #port 31
    "0x00 0x19 0x57 0xc 0x0"      #port 32
    "0x00 0x20 0x50 0x9 0x0"      #port 33
    "0x00 0x21 0x4f 0xc 0x0"      #port 34
    "0x00 0x24 0x4c 0xc 0x0"      #port 35
    "0x00 0x24 0x4c 0xc 0x0"      #port 36
    "0x00 0x24 0x4c 0xc 0x0"      #port 37
    "0x00 0x24 0x4c 0xc 0x0"      #port 38
    "0x00 0x24 0x4c 0xc 0x0"      #port 39
    "0x00 0x28 0x48 0xd 0x0"      #port 40
    "0x00 0x28 0x48 0xc 0x0"      #port 41
    "0x00 0x29 0x47 0xe 0x0"      #port 42
    "0x00 0x29 0x47 0xe 0x0"      #port 43
    "0x00 0x29 0x47 0xe 0x0"      #port 44
    "0x00 0x28 0x48 0xf 0x0"      #port 45
    "0x00 0x28 0x48 0xf 0x0"      #port 46
    "0x00 0x30 0x40 0xf 0x0"      #port 47
)

# TODO: need to change aoc si value when available
ce_aoc_si_value=( 
    "0x00 0x28 0x48 0xc 0x0"      #port  0  lane  0
    "0x00 0x29 0x41 0xc 0x0"      #port  0  lane  1 
    "0x00 0x29 0x41 0xf 0x0"      #port  0  lane  2 
    "0x00 0x29 0x41 0xc 0x0"      #port  0  lane  3 
    "0x00 0x28 0x42 0xc 0x0"      #port  1  lane  0
    "0x00 0x3a 0x36 0xf 0x0"      #port  1  lane  1 
    "0x00 0x2c 0x44 0xc 0x0"      #port  1  lane  2 
    "0x00 0x2c 0x44 0xc 0x0"      #port  1  lane  3 
    "0x00 0x2f 0x41 0xc 0x0"      #port  2  lane  0
    "0x00 0x38 0x38 0xc 0x0"      #port  2  lane  1 
    "0x00 0x2f 0x41 0xc 0x0"      #port  2  lane  2 
    "0x00 0x30 0x40 0xc 0x0"      #port  2  lane  3 
    "0x00 0x30 0x40 0xc 0x0"      #port  3  lane  0
    "0x00 0x3f 0x31 0xf 0x0"      #port  3  lane  1 
    "0x00 0x31 0x3f 0xc 0x0"      #port  3  lane  2 
    "0x00 0x30 0x40 0xa 0x0"      #port  3  lane  3 
    "0x00 0x30 0x40 0xc 0x0"      #port  4  lane  0
    "0x00 0x31 0x3f 0xf 0x0"      #port  4  lane  1 
    "0x00 0x2f 0x41 0xc 0x0"      #port  4  lane  2 
    "0x00 0x2e 0x42 0xc 0x0"      #port  4  lane  3 
    "0x00 0x30 0x40 0xe 0x0"      #port  5  lane  0
    "0x00 0x3f 0x31 0xf 0x0"      #port  5  lane  1 
    "0x00 0x38 0x38 0xf 0x0"      #port  5  lane  2 
    "0x00 0x3f 0x31 0xf 0x0"      #port  5  lane  3 
)

xe_dac_si_value=( 
    "0x00 0x3e 0x32 0xf 0x0"      #port  0 
    "0x00 0x3a 0x36 0xf 0x0"      #port  1 
    "0x00 0x3a 0x36 0xf 0x0"      #port  2
    "0x00 0x38 0x38 0xf 0x0"      #port  3
    "0x00 0x37 0x39 0xf 0x0"      #port  4
    "0x00 0x2e 0x42 0xf 0x0"      #port  5
    "0x00 0x33 0x3d 0xf 0x0"      #port  6
    "0x00 0x30 0x40 0xc 0x0"      #port  7
    "0x00 0x2f 0x43 0xe 0x0"      #port  8
    "0x00 0x2d 0x43 0xc 0x0"      #port  9
    "0x00 0x2c 0x44 0xc 0x0"      #port 10
    "0x00 0x2d 0x43 0xc 0x0"      #port 11
    "0x00 0x29 0x47 0xc 0x0"      #port 12
    "0x00 0x28 0x48 0xc 0x0"      #port 13
    "0x00 0x29 0x47 0xa 0x0"      #port 14
    "0x00 0x29 0x47 0xf 0x0"      #port 15
    "0x00 0x18 0x58 0x9 0x0"      #port 16
    "0x00 0x1d 0x53 0x9 0x0"      #port 17
    "0x00 0x1c 0x54 0x9 0x0"      #port 18
    "0x00 0x1c 0x54 0x9 0x0"      #port 19
    "0x00 0x1c 0x54 0x9 0x0"      #port 20
    "0x00 0x1c 0x54 0x9 0x0"      #port 21
    "0x00 0x1c 0x54 0x9 0x0"      #port 22
    "0x00 0x1c 0x54 0x9 0x0"      #port 23
    "0x00 0x1c 0x54 0x8 0x0"      #port 24
    "0x00 0x1c 0x54 0x8 0x0"      #port 25
    "0x00 0x18 0x58 0x8 0x0"      #port 26
    "0x00 0x18 0x58 0x8 0x0"      #port 27
    "0x00 0x14 0x5c 0x8 0x0"      #port 28
    "0x00 0x19 0x57 0x8 0x0"      #port 29
    "0x00 0x19 0x57 0x8 0x0"      #port 30
    "0x00 0x19 0x57 0x8 0x0"      #port 31
    "0x00 0x19 0x57 0xc 0x0"      #port 32
    "0x00 0x20 0x50 0x9 0x0"      #port 33
    "0x00 0x21 0x4f 0xc 0x0"      #port 34
    "0x00 0x24 0x4c 0xc 0x0"      #port 35
    "0x00 0x24 0x4c 0xc 0x0"      #port 36
    "0x00 0x24 0x4c 0xc 0x0"      #port 37
    "0x00 0x24 0x4c 0xc 0x0"      #port 38
    "0x00 0x24 0x4c 0xc 0x0"      #port 39
    "0x00 0x28 0x48 0xd 0x0"      #port 40
    "0x00 0x28 0x48 0xc 0x0"      #port 41
    "0x00 0x29 0x47 0xe 0x0"      #port 42
    "0x00 0x29 0x47 0xe 0x0"      #port 43
    "0x00 0x29 0x47 0xe 0x0"      #port 44
    "0x00 0x28 0x48 0xf 0x0"      #port 45
    "0x00 0x28 0x48 0xf 0x0"      #port 46
    "0x00 0x30 0x40 0xf 0x0"      #port 47
)

ce_dac_si_value=( 
    "0x00 0x28 0x48 0xc 0x0"      #port  0  lane  0
    "0x00 0x29 0x41 0xc 0x0"      #port  0  lane  1 
    "0x00 0x29 0x41 0xf 0x0"      #port  0  lane  2 
    "0x00 0x29 0x41 0xc 0x0"      #port  0  lane  3 
    "0x00 0x28 0x42 0xc 0x0"      #port  1  lane  0
    "0x00 0x3a 0x36 0xf 0x0"      #port  1  lane  1 
    "0x00 0x2c 0x44 0xc 0x0"      #port  1  lane  2 
    "0x00 0x2c 0x44 0xc 0x0"      #port  1  lane  3 
    "0x00 0x2f 0x41 0xc 0x0"      #port  2  lane  0
    "0x00 0x38 0x38 0xc 0x0"      #port  2  lane  1 
    "0x00 0x2f 0x41 0xc 0x0"      #port  2  lane  2 
    "0x00 0x30 0x40 0xc 0x0"      #port  2  lane  3 
    "0x00 0x30 0x40 0xc 0x0"      #port  3  lane  0
    "0x00 0x3f 0x31 0xf 0x0"      #port  3  lane  1 
    "0x00 0x31 0x3f 0xc 0x0"      #port  3  lane  2 
    "0x00 0x30 0x40 0xa 0x0"      #port  3  lane  3 
    "0x00 0x30 0x40 0xc 0x0"      #port  4  lane  0
    "0x00 0x31 0x3f 0xf 0x0"      #port  4  lane  1 
    "0x00 0x2f 0x41 0xc 0x0"      #port  4  lane  2 
    "0x00 0x2e 0x42 0xc 0x0"      #port  4  lane  3 
    "0x00 0x30 0x40 0xe 0x0"      #port  5  lane  0
    "0x00 0x3f 0x31 0xf 0x0"      #port  5  lane  1 
    "0x00 0x38 0x38 0xf 0x0"      #port  5  lane  2 
    "0x00 0x3f 0x31 0xf 0x0"      #port  5  lane  3 
)

#get field value in si value array for xe port
function get_xe_si {
    local port=$1
    local field=$2
    local type=$3
    local index=$port
    if [ "$type" == "${AOC_TYPE}" ]; then
        SI_VAL=$(echo "${xe_aoc_si_value[$index]}" | awk '{print $'$field'}')
    else
        SI_VAL=$(echo "${xe_dac_si_value[$index]}" | awk '{print $'$field'}')
    fi
}

#get field value in si value array for ce port
function get_ce_si {
    local port=$1
    local lane=$2
    local field=$3
    local type=$4
    index=$(( (${port}-1)*4+${lane} ))
    if [ "$type" == "${AOC_TYPE}" ]; then
        SI_VAL=$(echo "${ce_aoc_si_value[$index]}" | awk '{print $'$field'}')
    else
        SI_VAL=$(echo "${ce_dac_si_value[$index]}" | awk '{print $'$field'}')
    fi
}

# set si value for xe port
function _qsfp_xe_si_set {
    # convert PORT to xe port index
    local xe_port=$PORT
    # generate command for SI PRE value
    get_xe_si $xe_port $SI_PRE_IDX $TYPE 
    local pre_cmd="phy xe${xe_port} CL93N72_UT_CTL2r CL93N72_TXFIR_PRE=${SI_VAL}"
    # generate command for SI POST value
    get_xe_si $xe_port $SI_POST_IDX $TYPE
    local post_cmd="phy xe${xe_port} CL93N72_UT_CTL2r CL93N72_TXFIR_POST=${SI_VAL}"
    # generate command for SI MAIN value
    get_xe_si $xe_port $SI_MAIN_IDX $TYPE
    local main_cmd="phy xe${xe_port} CL93N72_UT_CTL3r CL93N72_TXFIR_MAIN=${SI_VAL}"
    # generate command for SI AMP CONTROL value
    get_xe_si $xe_port $SI_AMP_IDX $TYPE
    local amp_val=$SI_VAL
    get_xe_si $xe_port $SI_DRI_IDX $TYPE
    local dri_val=$SI_VAL
    local amp_cmd="phy xe${xe_port} AMS_TX_CTL2r AMS_TX_AMP_CTL=${amp_val} AMS_TX_DRIVERMODE=${dri_val}"
    # apply bcmcmd
    bcmcmd "${pre_cmd};${post_cmd};${main_cmd};${amp_cmd}"
}

# set aoc si value for ce port
function _qsfp_ce_si_set {
    # convert PORT to ce port index
    local ce_port=$(( $PORT - 48 ))
    for lane in {0..3};
    do
        # generate command for SI PRE value
        get_ce_si $ce_port $lane $SI_PRE_IDX $TYPE
        local pre_cmd="phy ce${ce_port} CL93N72_UT_CTL2r.${lane} CL93N72_TXFIR_PRE=${SI_VAL}"
        # generate command for SI POST value
        get_ce_si $ce_port $lane $SI_POST_IDX $TYPE
        local post_cmd="phy ce${ce_port} CL93N72_UT_CTL2r.${lane} CL93N72_TXFIR_POST=${SI_VAL}"
        # generate command for SI MAIN value
        get_ce_si $ce_port $lane $SI_MAIN_IDX $TYPE
        local main_cmd="phy ce${ce_port} CL93N72_UT_CTL3r.${lane} CL93N72_TXFIR_MAIN=${SI_VAL}"
        # generate command for SI AMP CONTROL value
        get_ce_si $ce_port $lane $SI_AMP_IDX $TYPE
        local amp_val=$SI_VAL
        get_ce_si $ce_port $lane $SI_AMP_IDX $TYPE
        local dri_val=$SI_VAL
        local amp_cmd="phy ce${ce_port} AMS_TX_CTL2r.${lane} AMS_TX_AMP_CTL=${amp_val} AMS_TX_DRIVERMODE=${dri_val}"
        # apply bcmcmd
        bcmcmd "${pre_cmd};${post_cmd};${main_cmd};${amp_cmd}"
    done
}

#QSFP SI value set  
function _qsfp_si_set {
    if [[ $PORT -le 47 && $PORT -ge 0 ]]; then
        # xe port
        _qsfp_xe_si_set
    else
        # ce port
        _qsfp_ce_si_set
    fi
}

function _util_input_check {
    # input parameter validation
    if [[ $1 -lt $2  || $1 -gt $3 ]]; then
        echo "Please input number $2~$3"
        exit
    fi
}

# Help usage function
function _help {
    echo "========================================================="
    echo "# Description: Help Function"
    echo "========================================================="
    echo "----------------------------------------------------"
    echo "EX       : ${0} help"
    echo "         : ${0} ${AOC_TYPE} [${MIN_PORT}-${MAX_PORT}]"
    echo "         : ${0} ${DAC_TYPE} [${MIN_PORT}-${MAX_PORT}]"
    echo "----------------------------------------------------"
}

#Main Function
function _main {

    # TODO: remove after SI value ready
    #exit ${TRUE}

    if [ -z $PORT ]; then
        _help
        exit ${FALSE}
    fi 

    if [ "${TYPE}" == "help" ]; then 
        _help
    elif [ "${TYPE}" == "${AOC_TYPE}" ] || [ "${TYPE}" == "${DAC_TYPE}" ]; then
        _util_input_check "$PORT" "$MIN_PORT" "$MAX_PORT"
        _qsfp_si_set
    else
        echo "Invalid Parameters, Exit!!!"
        _help
        exit ${FALSE}
    fi
}

_main
